/**
 * 2010(c) Copyright Oceansoft Information System Co.,LTD. All rights reserved.
 * <p>
 * Compile: JDK 1.6+
 * <p>
 * 版权所有(C)：江苏欧索软件有限公司
 * <p>
 * 公司名称：江苏欧索软件有限公司
 * <p>
 * 公司地址：中国苏州科技城青山路1号
 * <p>
 * 网址: http://www.oceansoft.com.cn
 * <p>
 * 作者: 090922(陈伟)
 * <p>
 * 文件名: com.oceansoft.mobile.econsole.common.util.HttpClient.java 
 * <p>
 * 类产生时间: 2014-7-9 0009 下午 15:03
 * <p>
 * 负责人: 090922(陈伟)
 * <p>
 * Email:javacspring@gmail.com
 * <p>
 * 所在组 : 掌上公安应用平台
 * <p>
 * 所在部门: 开发部--手持技术部
 * <p>
 * <p>
 */
package cn.com.oceansoft.application.common.util;

import com.alibaba.fastjson.JSON;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.FileEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * HttpClient请求工具类
 *
 * @author: huqp
 * @time: 2016-5-23 下午 13:18
 */
public class HttpClientUtil {

    private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);

    public static final String CHARSET = "UTF-8";

    public static final String token = "kong_plugin_token";

    private static final CloseableHttpClient httpClient;


    public static CloseableHttpClient getClient() {
        return httpClient;
    }

    /**
     * 执行put请求
     * @param url
     * @return
     * @throws IOException
     */
    public static String doPut(String url, Object data)
            throws IOException {
        //String token = TokenUtils.getInstance().getToken(url);
        String result = null;
        HttpClient htpClient = new HttpClient();
        PutMethod putMethod = new PutMethod(url);
        putMethod.addRequestHeader("token",token);
        putMethod.addRequestHeader( "Content-Type","application/json" );
        putMethod.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
        putMethod.setRequestBody(JSON.toJSONString(data));

        try {
            if (logger.isDebugEnabled()) {
                logger.debug(url);
            }
            int statusCode = htpClient.executeMethod(putMethod);
            if (HttpStatus.SC_OK != statusCode) {
                putMethod.releaseConnection();
                if (logger.isDebugEnabled())
                    logger.debug("HttpPut error,status code:" + statusCode);
                throw new HttpException("HttpPut error,status code:" + statusCode);
            }
            byte[] responseBody = putMethod.getResponseBody();
            result = new String(responseBody,"UTF-8");
        } finally {
            putMethod.releaseConnection();
        }
        return result;
    }
    /**
     * 执行put请求
     * @param url
     * @return
     * @throws IOException
     */
    public static String doPatch(String url, Object data,ContentType type){
        try {
//            String token = TokenUtils.getInstance().getToken(url);
            HttpPatch httpPatch = new HttpPatch(url);
            httpPatch.setHeader("token",token);
            if(data!=null) {
                if(ContentType.APPLICATION_JSON.equals(type)) {
                    httpPatch.setEntity(new StringEntity(JSON.toJSONString(data), ContentType.APPLICATION_JSON));
                }else if(ContentType.APPLICATION_FORM_URLENCODED.equals(type)){
                    if(data instanceof Map) {
                        Map<String,String> params= (Map<String, String>) data;
                        if (params != null && !params.isEmpty()) {
                            List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
                            for (Map.Entry<String, String> entry : params.entrySet()) {
                                String value = entry.getValue();
                                if (value != null) {
                                    pairs.add(new BasicNameValuePair(entry.getKey(), value));
                                }
                            }
                            httpPatch.setEntity(new UrlEncodedFormEntity(pairs,CHARSET));
                        }
                    }
                }
            }
            CloseableHttpResponse response = httpClient.execute(httpPatch);
            try {
                HttpEntity entity = response.getEntity();
                System.out.println("HttpEntity=====>" + entity);
                if (null != entity) {return EntityUtils.toString(entity);}
                return null;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            } finally {
                release(response, httpPatch);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 执行GET请求
     *
     * @param url GET请求URL字符串
     * @return 响应字符串
     * @throws HttpException 传入参数或返回状态码非200时抛出运行时错误
     */
    public static String doGet(String url) {

//      String token = TokenUtils.getInstance().getToken(url);
        String result = null;
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("token",token);
        CloseableHttpResponse response = null;
        try {
            if (logger.isDebugEnabled())
                logger.debug(url);
            try {
                response = httpClient.execute(httpGet);
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
            int statusCode = response.getStatusLine().getStatusCode();
            if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
                release(response, httpGet);
                if (logger.isDebugEnabled())
                    logger.debug("HttpGet error,status code:" + statusCode);
                return null;
            }
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                try {
                    result = EntityUtils.toString(entity, "utf-8");
                    EntityUtils.consume(entity);
                } catch (IOException e) {
                    e.printStackTrace();
                    return null;
                }
            }
        } finally {
            release(response, httpGet);
        }
        return result;
    }


    /**
     * 执行带参数Get请求
     *
     * @param url    请求URL地址
     * @param params 请求参数，参数个数必须为偶数且数据类型为String,Char,int，否则产生错误<br>如："name","Tom","age",12
     * @return 响应内容
     * @throws IOException
     */
    public static String doGet(String url, Object... params){
        return doGet(processParams(url, params));
    }
    public static String doGet(String url, Map<String,String> map) {
        return doGet(processGetParams(url,map,CHARSET));
    }
    public static String doGet(String url, Map<String,String[]> map,String charset) {
        Map<String,String> newMap=new HashMap<>();
        for (Map.Entry<String, String[]> entry : map.entrySet()) {
            String[] value = entry.getValue();
            if (value != null) {
                for (int i=0;i<value.length;i++){
                    newMap.put(entry.getKey(),value[i]);
                }
            }
        }
        return doGet(processGetParams(url,newMap,charset==null?CHARSET:charset));
    }

    /**
     * POST请求StringEntity数据
     *
     * @param url  请求URL地址
     * @param data 请求JSON数据
     * @return String 响应JSON字符串
     * @throws IOException
     */
    public static String doPostString(String url, Object data) {
        try {
//            String token = TokenUtils.getInstance().getToken(url);
            HttpPost httpPost = new HttpPost(url);
            httpPost.setHeader("token",token);
            httpPost.setEntity(new StringEntity(JSON.toJSONString(data), ContentType.APPLICATION_JSON));
            CloseableHttpResponse response = httpClient.execute(httpPost);
            try {
                HttpEntity entity = response.getEntity();
                System.out.println("HttpEntity=====>" + entity);
                if (null != entity) {
                    return EntityUtils.toString(entity);
                }
                return null;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            } finally {
                release(response, httpPost);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
    public static String doTransfer(HttpEntityEnclosingRequestBase method, Object data,ContentType type) {
        try {
//            String token = TokenUtils.getInstance().getToken(url);
            method.setHeader("token",token);
            if(data!=null) {
                if(ContentType.APPLICATION_JSON.equals(type)) {
                    method.setEntity(new StringEntity(JSON.toJSONString(data), ContentType.APPLICATION_JSON));
                }else if(ContentType.APPLICATION_FORM_URLENCODED.equals(type)){
                    if(data instanceof Map) {
                        Map<String,String> params= (Map<String, String>) data;
                        if (params != null && !params.isEmpty()) {
                            List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
                            for (Map.Entry<String, String> entry : params.entrySet()) {
                                String value = entry.getValue();
                                if (value != null) {
                                    pairs.add(new BasicNameValuePair(entry.getKey(), value));
                                }
                            }
                            method.setEntity(new UrlEncodedFormEntity(pairs,CHARSET));
                        }
                    }
                }
            }
            CloseableHttpResponse response = httpClient.execute(method);
            try {
                HttpEntity entity = response.getEntity();
                System.out.println("HttpEntity=====>" + entity);
                if (null != entity) {
                    return EntityUtils.toString(entity);
                }
                return null;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            } finally {
                release(response, method);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

//
    public static String doPostFile(String url,File uploadFile){
//        String token = TokenUtils.getInstance().getToken(url);
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("token",token);
        if (null != uploadFile && uploadFile.length() > 0) {

            FileEntity fileEntity = new FileEntity(uploadFile, ContentType.MULTIPART_FORM_DATA);
            httpPost.setEntity(fileEntity);
        }
        StringBuffer sb = new StringBuffer();
        try {
            CloseableHttpResponse closeableHttpResponse = httpclient.execute(httpPost);
            InputStream inputStream = closeableHttpResponse.getEntity().getContent();
            Reader reader = new InputStreamReader(inputStream, "UTF-8");

            BufferedReader bufferedReader = new BufferedReader(reader);
            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                sb.append(str);
            }
        } catch (IOException e) {
            logger.error("上传文件异常,获取地址：{}失败，错误信息如下：{}", url, e.getMessage());
        } finally {
            try {
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();

    }

    public static String  uploadFile(String url,File file) {
//        String token = TokenUtils.getInstance().getToken(url);
        String result = null;
        if (!file.exists()) {
            return result;
        }
        PostMethod postMethod = new PostMethod(url);
        postMethod.addRequestHeader("token",token);
        try {
            //FilePart：用来上传文件的类
            FilePart fp = new FilePart("materialFile", file);
            Part[] parts = { fp };

            //对于MIME类型的请求，httpclient建议全用MulitPartRequestEntity进行包装
            MultipartRequestEntity mre = new MultipartRequestEntity(parts, postMethod.getParams());
            postMethod.setRequestEntity(mre);
            HttpClient client = new HttpClient();
            client.getHttpConnectionManager().getParams().setConnectionTimeout(50000);// 设置连接时间
            int status = client.executeMethod(postMethod);
            if (status == HttpStatus.SC_OK) {
                result = postMethod.getResponseBodyAsString();
            } else {
                System.out.println("fail");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放连接
            postMethod.releaseConnection();
        }
        return result;
    }

    public static CloseableHttpResponse getHttpResponse(String url, Map<String, String> params) {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        try {
            url = processGetParams(url, params, CHARSET);
            HttpGet httpGet = new HttpGet(url);
            System.out.println("URL===>" + url);
            CloseableHttpResponse response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpGet.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            return response;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 处理GET参数
     *
     * @param url     请求的url地址 ?之前的地址
     * @param params  请求参数
     * @param charset 请求参数字符集
     * @return String
     * @throws IOException
     */
    private static String processGetParams(String url, Map<String, String> params, String charset){
        if (params != null && !params.isEmpty()) {
            List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
            for (Map.Entry<String, String> entry : params.entrySet()) {
                String value = entry.getValue();
                if (value != null) {
                    pairs.add(new BasicNameValuePair(entry.getKey(), value));
                }
            }
            try {
                url += "?" + EntityUtils.toString(new UrlEncodedFormEntity(pairs, charset));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return url;
    }

    /**
     * 处理请求参数
     * <br> 请求参数以可变参数形式传入，其中奇数位参数为key，偶数位参数为value.
     * <br>如：processParams("http://172.17.100.139/econsole/api/profile","name","tom","age",12,"height",188)
     *
     * @param baseUrl 资源地址
     * @param params  请求参数
     * @return String 完整请求URL 如：http://172.17.100.139/econsole/api/profile?name=tom&age=12&height=188
     * @throws IllegalArgumentException
     */
    private static String processParams(String baseUrl, Object... params) throws IllegalArgumentException {
        int len = params.length;
        StringBuilder rt = new StringBuilder(baseUrl);
        if (len > 1 && 0 == len % 2) {
            for (int i = 0; i < len; i++) {
                Object obj = params[i];
                if (obj instanceof Integer || obj instanceof String || obj instanceof Character) {
                    if (i == 0) {
                        rt.append("?");
                    } else {
                        rt.append("&");
                    }
                    rt.append(params[i]).append("=");
                    i++;
                    rt.append(params[i]);
                } else {
                    throw new IllegalArgumentException("参数类型错误，仅允许String,Character,Integer类型参数");
                }
            }
        } else if (len == 0) {
            return baseUrl;
        } else {
            throw new IllegalArgumentException("参数不正确，传入参数量必须为偶数");
        }
        return rt.toString();
    }


    /**
     * 执行delete请求
     * @param url
     * @return
     * @throws IOException
     */
    public static String doDel(String url, Object... params)
            throws IOException {
        return doDel(processParams(url,params));

    }

    public static String doDel(String url){
//        String token = TokenUtils.getInstance().getToken(url);
        String result = null;
        HttpClient htpClient = new HttpClient();
        DeleteMethod deleteMethod = new DeleteMethod(url);
        deleteMethod.addRequestHeader("token",token);
        try {
            if (logger.isDebugEnabled()) {
                logger.debug(url);
            }
            int statusCode = 0;
            try {
                statusCode = htpClient.executeMethod(deleteMethod);
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
            if (HttpStatus.SC_OK != statusCode) {
                deleteMethod.releaseConnection();
                if (logger.isDebugEnabled())
                    logger.debug("HttpPut error,status code:" + statusCode);
                return null;
            }
            byte[] responseBody = new byte[0];
            try {
                responseBody = deleteMethod.getResponseBody();
                result = new String(responseBody,"UTF-8");
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        } finally {
            deleteMethod.releaseConnection();
        }
        return result;
    }
    public static String doDelete(String url) throws IOException{

        String result = null;
        HttpDelete httpDelete = new HttpDelete(url);
        CloseableHttpResponse response = null;
        try {
            if (logger.isDebugEnabled())
                logger.debug(url);
            response = httpClient.execute(httpDelete);
            int statusCode = response.getStatusLine().getStatusCode();
            if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
                release(response, httpDelete);
                if (logger.isDebugEnabled())
                    logger.debug("HttpGet error,status code:" + statusCode);
                throw new HttpException("HttpGet error,status code:" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                result = EntityUtils.toString(entity, "utf-8");
            }
            EntityUtils.consume(entity);
        } finally {
            release(response, httpDelete);
        }
        return result;
    }





    /**
     * 释放链接资源
     *
     * @param response   响应流
     * @param httpMethod 执行请求方法
     */
    private static void release(Closeable response, HttpRequestBase httpMethod) {
        if (null != response) {
            try {
                response.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            httpMethod.abort();
            httpMethod.releaseConnection();
        }
    }

    static {
        PoolingHttpClientConnectionManager pcm = new PoolingHttpClientConnectionManager();
        pcm.setMaxTotal(200);
        pcm.setDefaultMaxPerRoute(pcm.getMaxTotal());
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(120000).setSocketTimeout(150000).build();
        httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
    }

    /**
     * 执行GET请求
     * @param url GET请求URL字符串
     * @return 响应字符串
     * @throws HttpException 传入参数或返回状态码非200时抛出运行时错误
     */
    public static String doGetToken(String url) throws IOException, IllegalArgumentException {


        if (null == url || url.trim().length() == 0) {
            throw new HttpException("URL地址错误");
        }
        String result = null;
        HttpGet httpGet = new HttpGet(url);
        CloseableHttpResponse response = null;
        try {
            if (logger.isDebugEnabled())
                logger.debug(url);
            response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
                release(response, httpGet);
                if (logger.isDebugEnabled())
                    logger.debug("HttpGet error,status code:" + statusCode);
                throw new HttpException("HttpGet error,status code:" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                result = EntityUtils.toString(entity, "utf-8");
            }
            EntityUtils.consume(entity);
        } finally {
            release(response, httpGet);
        }
        return result;
    }

    /**
     * POST请求StringEntity数据
     *
     * @param url  请求URL地址
     * @param data 请求JSON数据
     * @return String 响应JSON字符串
     * @throws IOException
     */
    public static String doPostTokenString(String url, Object data) {
        try {
            String a = JSON.toJSONString(data);
            HttpPost httpPost = new HttpPost(url);
            httpPost.setEntity(new StringEntity(JSON.toJSONString(data), ContentType.APPLICATION_JSON));
            CloseableHttpResponse response = httpClient.execute(httpPost);
            try {
                HttpEntity entity = response.getEntity();
                System.out.println("HttpEntity=====>" + entity);
                if (null != entity) {
                    return EntityUtils.toString(entity);
                }
                return null;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            } finally {
                release(response, httpPost);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

}
